Analysis of Cyber-security Threats

Abstract

The purpose of this data analysis was to find the most efficient model for predicting financial loss due to cyber security attacks. Cyber security attacks effect a number of different types of industries and can be harmful not only to the privacy of the company, but can also contribute to company losses. This analysis will explore LASSO, Ridge and Elastic Net linear regression to find an optimal model in predicting financial loss. It will also explore support vector regression to fit the data to a certain margin of error and minimize complexity of the model.

Introduction

How much money can be lost in a single cyber security threat? By modeling and observing trends in cyber security threat data, this analysis seeks to help reduce the financial impact of cyber security threats. Limitations of this analysis include under reporting and data bias. Many organizations will not report security breaches publicly to avoid damage to their reputation. As well, threats can evolve quickly, leading to models becoming outdated rapidly.

Overview of Data

The dataset was obtained from Kaggle and contains 10 variables that are potential significant covariates in predicting potential threats. The variable country refers to the country where the attack occurred. The other variables analyze incident resolution time in hours, number of affected users, financial loss, attack type, target industry, attack source, security vulnerability type and defense mechanism used. Here is a full list of variables:

  • Country country where the attack occurred
  • Year year of the incident
  • Attack Type type of cyber-security threat
  • Target Industry industry targeted
  • Financial Loss estimated financial loss in millions
  • Number of Affected Users number of users impacted by the attack
  • Attack Source origin of the attack
  • Security Vulnerability Type type of vulnerability exploited
  • Defense Mechanism Used cyber-security defense strategy applied
  • Incident Resolution Time time taken to fully resolve event in hours
cyber <- read.csv('https://raw.githubusercontent.com/GabbyK8/Datasets/refs/heads/main/Global_Cybersecurity_Threats_2015-2024.csv')
cyber$Defense.Mechanism.Used <- ifelse(cyber$Defense.Mechanism.Used == "AI-based Detection", "AI", cyber$Defense.Mechanism.Used)

# plot 1 number of affected users by financial loss by vulnerability type


ggplot(cyber, aes(x = cyber$Number.of.Affected.Users, y = cyber$Financial.Loss..in.Million..., color = cyber$Security.Vulnerability.Type)) +
geom_smooth(aes(x = cyber$Number.of.Affected.Users, y = cyber$Financial.Loss..in.Million..., color = cyber$Security.Vulnerability.Type), method = "lm", se = FALSE) +
  scale_size(range = c(2, 10)) +
  labs(
    title = "Plot of Security Vulnerability, Volume Compromised, and Financial Impact",
    x = "Volume Compromised",
    y = "Financial Impact",
    color = "Security Vulernability"
  ) +
  theme_minimal()
This plot shows the relationship between security vulnerability type and the interaction between the number of affected users and financial loss in millions. In most cases the number of affected users seems to be positively correlated with financial loss. The only exception is seen in zero-day. zero-day refers to a type of vulnerability where the target of the attack is unaware of the attack. Meaning there are zero days for the problem to be solved before it has been exploited. It would make sense that in this type of vulnerability, the fewer users affected would lead to a greater financial loss.

This plot shows the relationship between security vulnerability type and the interaction between the number of affected users and financial loss in millions. In most cases the number of affected users seems to be positively correlated with financial loss. The only exception is seen in zero-day. zero-day refers to a type of vulnerability where the target of the attack is unaware of the attack. Meaning there are zero days for the problem to be solved before it has been exploited. It would make sense that in this type of vulnerability, the fewer users affected would lead to a greater financial loss.

# plot 3 Density plot of attacked industries
Year_data <- cyber %>%
  filter(Year == 2015)
p1<- ggplot(Year_data, aes(x = Number.of.Affected.Users, fill = Country)) +
  geom_density(alpha = 0.6) +
  labs(
    x = "Number of Affected Users",
    y = "Density",
    fill="Country",
    title = "Density Plot of Attacked Countries in 2015"
  ) +
  theme_minimal()
ggplotly(p1)

This plot shows the density of number of affected users in cybersecurity attacks in each country in the year 2015.

 Year_data1 <- cyber %>%
  filter(Year == 2024)
# plot 4 Density plot of Attacked countries
p2 <- ggplot(Year_data1, aes(x = Number.of.Affected.Users, fill = Country)) +
  geom_density(alpha = 0.6) +
  labs(
    x = "Number of Affected Users",
    y = "Density",
    fill="Country",
    title = "Density Plot of Attacked Countries in 2024"
  ) +
  theme_minimal()
ggplotly(p2)

This plot shows the density of number of affected users in cybersecurity attacks in each country in the year 2024.

Each country is given a specific color and the number of affected users is displayed on the x-axis. The density is displayed on the y-axis. Density in this plot shows the relative frequency of number of affected users per attack in each country.In 2015, the cyber attacks within the USA more frequently affected about 310,000 users, compared to Russia where attacks more frequently attacked 670,000 users and Germany where most attacks more frequently affected 790,000 users. In 2024, the number of affected users in the USA does not seem to be much more dense in any one number and is more dispersed. Japan had more frequent attacks that affected 500,000 and Brazil had it’s most frequent at 750,000 users.

ggplot(cyber, aes(x = cyber$Year, y = cyber$Incident.Resolution.Time..in.Hours., color = cyber$Security.Vulnerability.Type)) +
geom_smooth(aes(x = cyber$Year, y = cyber$Incident.Resolution.Time..in.Hours., color = cyber$Security.Vulnerability.Type), method = "lm", se = FALSE) +
  scale_size(range = c(2, 10)) +
  labs(
    title = "Plot of Security Vulnerability, Year of Attack, and Resolution Time",
    x = "Year of Attack",
    y = "Incident Resolution Time in Hours",
    color = "Security Vulernability"
  ) +
  theme_minimal()
This plot shows the relationship between security vulnerability type and the interaction between the year of attack and resolution time. The plot shows how over the years resolution time has improved for certain vulnerability types, such as weak passwords, unpatched software, and social engineering. However, for zero-day there is an increase in resolution time, showing a positive relationship between zero-day and resolution time.

This plot shows the relationship between security vulnerability type and the interaction between the year of attack and resolution time. The plot shows how over the years resolution time has improved for certain vulnerability types, such as weak passwords, unpatched software, and social engineering. However, for zero-day there is an increase in resolution time, showing a positive relationship between zero-day and resolution time.

#plot of zero-day attack type by target industry
zero_data <- cyber %>%
  filter(Security.Vulnerability.Type == "Zero-day") 
a <- ggplot(zero_data, aes(x = zero_data$Attack.Type, fill =zero_data$Target.Industry )) +
  geom_bar(position = "dodge") +
  labs(
    x = "Threat Type",
    y = "Proportion",
    fill = "Target Industry",
    title = "Zero-day Incidences by Threat Type vs. Target Industry"
  ) +
  theme_minimal()
ggplotly(a)

This plot focuses on zero-day vulnerability and shows the proportion of threat types in each industry. The x-axis shows each threat type and the y-axis shows the proportion of attacks within the dataset that fall into each category. The different colors are meant to show a subcategory, target industry. This shows the proportion of the dataset that falls within each category of threat type in each target industry.

Zero-day attacks seem to commonly use Phising within both retail and IT industries, based on the height and count of the bar in these two categories. Ransomware is the most minimally used zero-day attack on the government, with a count of just 12.

col0=c("#4682B4", "#B4464B","#9900FF","#FF66FF", "#009933")
boxplot(Incident.Resolution.Time..in.Hours. ~ Defense.Mechanism.Used,
        data=cyber,
        xlab="Defense Mechanism",
        ylab="Resolution Time (hours)",
        col = col0,
        main="Incident Resolution Time by Defense Mechanism",
        cex.main = 0.9,
        col.main = "blue")
The bloxplot shows the relationship between defense mechanism and resolution time in hours.

The bloxplot shows the relationship between defense mechanism and resolution time in hours.

The boxplot shows that the average resolution time among attacks based on defense mechanisms is relatively the same. The only exception seems to be firewall, which appears to take slightly less resolution time on average.We can indicate the average by looking the black horizontal line within each box. They all appear to line up with one another indicating similar averages.

Skewness

cyber$Country[cyber$Country=="USA"]<-1
cyber$Country<- ifelse(cyber$Country!="USA",0)
cyber$Security.Vulnerability.Type[cyber$Security.Vulnerability.Type=="Zero-day"]<-1
cyber$Security.Vulnerability.Type<-ifelse(cyber$Security.Vulnerability.Type!="Zero-day",0)
cyber$Number.of.Affected.Users<-as.numeric(cyber$Number.of.Affected.Users)
cyber$Year<-as.numeric(as.factor(cyber$Year))
cyber$Incident.Resolution.Time..in.Hours.<-as.numeric(cyber$Incident.Resolution.Time..in.Hours.)


c<-skewness(cyber$Financial.Loss..in.Million...)
d<-skewness(cyber$Number.of.Affected.Users)
e<-skewness(cyber$Year) 

Skewness = cbind(Financial.Loss = c, 
                 Affected.Users =  d, 
                 Year = e)

pander(Skewness)
Financial.Loss Affected.Users Year
-0.01684 -0.02537 -0.02749

The data is normally skewed and no transformation is necessary.

Regularized Regression Modeling

For this analysis, we will explore three types of regularized linear regression modeling to find key predictors for financial loss from cyber security attacks.

# Predictors (x) and Response Variable (y)

set.seed(12345)
X <- as.data.frame(cyber[, -5])  

y <- cyber$Financial.Loss..in.Million...


train_index <- createDataPartition(y, p = 0.8, list = FALSE)
X_train <- makeX(X[train_index, ])
X_test <- makeX(X[-train_index, ])
y_train <- y[train_index]
y_test <- y[-train_index]

#standardizing the data
preprocess_params <- preProcess(X_train, method = c("center","scale"))
X_train <- predict(preprocess_params, X_train)
X_test <- predict(preprocess_params, X_test)


#fitting the model
fit_lasso <- glmnet(X_train, y_train, alpha = 1)  # Lasso
fit_ridge <- glmnet(X_train, y_train, alpha = 0)  # Ridge
fit_elastic_net <- glmnet(X_train, y_train, alpha = 0.5)  # Elastic Net
#cross-validation
cv_lasso <- cv.glmnet(X_train, y_train, alpha = 1)       # Lasso CV
cv_ridge <- cv.glmnet(X_train, y_train, alpha = 0)       # Ridge CV
cv_elastic_net <- cv.glmnet(X_train, y_train, alpha = 0.5)  # Elastic Net CV

#plot coefficient path
par(mar=c(5,4,6,3))
# Plot coefficient path
plot(fit_lasso, xvar = "lambda", label = TRUE,
     lwd = 1.5,
     main = "Coefficient Path Analysis: LASSO",
     cex.main = 0.9,
     col = rainbow(10))
abline(v = log(1), col = "purple", lty = 4, lwd = 2)
abline(v = -1, col = "steelblue", lty = 2, lwd = 2)
The x-axis of the coefficient path analysis shows the log of lambda. A low lambda has less regularization and is closer to ordinary least squares. A high lambda indicates higher regularization and at this lambda many coefficients will shrink to zero. The Y-axis shows the coefficient values for each variable predictor for financial loss. The lines shows the path of each coefficient has lambda differs. The dashed line shows the optimal level of shrinkage. Coefficients to the right of this line are more forced towards zero. At this chosen lambda only certain variables will be non-zero and are deemed significant.

The x-axis of the coefficient path analysis shows the log of lambda. A low lambda has less regularization and is closer to ordinary least squares. A high lambda indicates higher regularization and at this lambda many coefficients will shrink to zero. The Y-axis shows the coefficient values for each variable predictor for financial loss. The lines shows the path of each coefficient has lambda differs. The dashed line shows the optimal level of shrinkage. Coefficients to the right of this line are more forced towards zero. At this chosen lambda only certain variables will be non-zero and are deemed significant.

pander(data.frame(colnames(X_train)[c(27, 5, 20, 12)]),caption= "Feature Variables at log(Lambda) = 0")
Feature Variables at log(Lambda) = 0
colnames.X_train..c.27..5..20..12..
Incident.Resolution.Time..in.Hours.
Attack.TypeMan-in-the-Middle
Attack.SourceUnknown
Target.IndustryHealthcare
pander(data.frame(colnames(X_train)[c(18, 12, 10, 24, 5, 23, 17, 11, 3)]),caption= " Feature Variables at log(Lambda) = -1")
Feature Variables at log(Lambda) = -1
colnames.X_train..c.18..12..10..24..5..23..17..11..3..
Attack.SourceInsider
Target.IndustryHealthcare
Target.IndustryEducation
Defense.Mechanism.UsedEncryption
Attack.TypeMan-in-the-Middle
Defense.Mechanism.UsedAntivirus
Attack.SourceHacker Group
Target.IndustryGovernment
Attack.TypeDDoS

The table above displays the feature variables observed in the Coefficient Analysis plot.

par(mar=c(5,4,6,3))
##
plot(cv_lasso, main = "RMSE Plot: LASSO",
     cex.main = 0.9)
The plot of performance shows that as lambda increases, the MSE decreases. The two vertical lines give a reference of lambda.

The plot of performance shows that as lambda increases, the MSE decreases. The two vertical lines give a reference of lambda.

# Extract coefficients for the best lambda
best.lasso.lambda <- cv_lasso$lambda.min
best.ridge.lambda <- cv_ridge$lambda.min
best.elastic.net.lambda <- cv_elastic_net$lambda.min
##
# Lasso Regression (L1 Regularization): 
# CAUTION: model formula differs from the regular regression formula 
lasso_model.opt <- glmnet(X_train, 
                      y_train, 
                      alpha = 1,      # lasso regression 
                      lambda = best.lasso.lambda,standardize = TRUE)   # useser selected alpha, optimal lambda
                                    # can be obtained through CV (see below)
lasso_predictions.opt <- predict(lasso_model.opt, 
                             s = best.lasso.lambda, # user selected lambda value 
                                      # (regularization paremeter)
                             newx = X_test)  # test data set 
# The following RMSE of prediction serves as a validation - one step validation
lasso_rmse.opt <- sqrt(mean((y_test - lasso_predictions.opt)^2))   
                                          
# Ridge Regression (L2 Regularization)
ridge_model.opt <- glmnet(X_train, y_train, alpha = 0, lambda = best.ridge.lambda,standardize=TRUE)
ridge_predictions.opt <- predict(ridge_model.opt, s = best.ridge.lambda, newx = X_test)
ridge_rmse.opt <- sqrt(mean((y_test - ridge_predictions.opt)^2))

# Elastic Net (Combination of L1 and L2)
elastic_net_model.opt <- glmnet(X_train, y_train, alpha = 0.5, lambda = 0.1,standardize = TRUE)
elastic_net_predictions.opt <- predict(elastic_net_model.opt, s = 0.1, newx = X_test)
elastic_net_rmse.opt <- sqrt(mean((y_test - elastic_net_predictions.opt)^2))

RMSE.opt = cbind(LASSO.opt = lasso_rmse.opt, 
                 Ridge.opt =  ridge_rmse.opt, 
                 Elasticnet.opt = elastic_net_rmse.opt)

pander(RMSE.opt)
LASSO.opt Ridge.opt Elasticnet.opt
28.79 28.72 28.89

The optimal lambda for each type of linear regression is shown above.

LASSO Regression Equation

Now, a final model will be extracted using LASSO, Ridge, and Elastic Net.

#Lasso
# Extract coefficients with names from glmnet
coef_lasso <- coef(cv_lasso, s = best.lasso.lambda)
coef_df <- as.data.frame(as.matrix(coef_lasso))
coef_df$feature <- rownames(coef_df)
colnames(coef_df)[1] <- "coefficient"

# Filter non-zero coefficients
nonzero_coefs <- subset(coef_df, coefficient != 0)

# Separate intercept
intercept <- round(nonzero_coefs$coefficient[nonzero_coefs$feature == "(Intercept)"], 4)
nonzero_terms <- subset(nonzero_coefs, feature != "(Intercept)")

# Build model equation string
equation <- paste0(round(nonzero_terms$coefficient, 4), "*", nonzero_terms$feature)
cat("Model equation: y =", intercept, "+", paste(equation, collapse = " + "), "\n")
Model equation: y = 50.5369 + 0.6683*Attack.TypeDDoS + -0.4171*Target.IndustryEducation + 0.6626*Target.IndustryGovernment + -0.3464*Target.IndustryHealthcare + 0.265*Attack.SourceHacker Group + -0.5335*Attack.SourceInsider + 0.0065*Defense.Mechanism.UsedAntivirus 

Ridge Regression Equation

# Extract coefficients with names from glmnet
coef_ridge <- coef(cv_ridge, s = best.ridge.lambda)
coef_df <- as.data.frame(as.matrix(coef_ridge))
coef_df$feature <- rownames(coef_df)
colnames(coef_df)[1] <- "coefficient"

# Filter non-zero coefficients
nonzero_coefs <- subset(coef_df, coefficient != 0)

# Separate intercept
intercept <- round(nonzero_coefs$coefficient[nonzero_coefs$feature == "(Intercept)"], 4)
nonzero_terms <- subset(nonzero_coefs, feature != "(Intercept)")

# Build model equation string
equation <- paste0(round(nonzero_terms$coefficient, 4), "*", nonzero_terms$feature)
cat("Model equation: y =", intercept, "+", paste(equation, collapse = " + "), "\n")
Model equation: y = 50.5369 + 0.0114*Year + 0.0521*Attack.TypeDDoS + -0.0125*Attack.TypeMalware + 0.0145*Attack.TypeMan-in-the-Middle + -0.0171*Attack.TypePhishing + -0.0201*Attack.TypeRansomware + -0.0186*Attack.TypeSQL Injection + 7e-04*Target.IndustryBanking + -0.0445*Target.IndustryEducation + 0.0576*Target.IndustryGovernment + -0.0398*Target.IndustryHealthcare + 0.0036*Target.IndustryIT + 0.0055*Target.IndustryRetail + 0.0187*Target.IndustryTelecommunications + 6e-04*Number.of.Affected.Users + 0.0427*Attack.SourceHacker Group + -0.0496*Attack.SourceInsider + 0.0182*Attack.SourceNation-state + -0.0106*Attack.SourceUnknown + -0.0045*Defense.Mechanism.UsedAI + 0.0233*Defense.Mechanism.UsedAntivirus + -0.0193*Defense.Mechanism.UsedEncryption + 0.0027*Defense.Mechanism.UsedFirewall + -0.0029*Defense.Mechanism.UsedVPN + -0.0122*Incident.Resolution.Time..in.Hours. 

Elastic Net Regression Equation

# Extract coefficients with names from glmnet
coef_elastic <- coef(cv_elastic_net, s = best.elastic.net.lambda)
coef_df <- as.data.frame(as.matrix(coef_elastic))
coef_df$feature <- rownames(coef_df)
colnames(coef_df)[1] <- "coefficient"

# Filter non-zero coefficients
nonzero_coefs <- subset(coef_df, coefficient != 0)

# Separate intercept
intercept <- round(nonzero_coefs$coefficient[nonzero_coefs$feature == "(Intercept)"], 4)
nonzero_terms <- subset(nonzero_coefs, feature != "(Intercept)")

# Build model equation string
equation <- paste0(round(nonzero_terms$coefficient, 4), "*", nonzero_terms$feature)
cat("Model equation: y =", intercept, "+", paste(equation, collapse = " + "), "\n")
Model equation: y = 50.5369 + 0.4941*Attack.TypeDDoS + -0.2438*Target.IndustryEducation + 0.5433*Target.IndustryGovernment + -0.168*Target.IndustryHealthcare + 0.1465*Attack.SourceHacker Group + -0.3984*Attack.SourceInsider 
lasso.error <- min(cv_lasso$cvm)
ridge.error <- min(cv_ridge$cvm)
enet.error  <- min(cv_elastic_net$cvm)

model.errors <- data.frame(
  Model = c("LASSO", "Ridge", "Elastic Net"),
  CV_Error = c(lasso.error, ridge.error, enet.error)
)

pander(model.errors)
Model CV_Error
LASSO 829.7
Ridge 829.9
Elastic Net 830.3

Conclusion for Regularized Regression Modeling

The table above shows the MSE values or cross-validated errors for our three models. A smaller value indicates a model with greater performance. The LASSO linear regression model out performs both the Ridge and Elastic Net model. When predicting financial loss caused by cyber security threats, the LASSO liner regression model will be the most efficient.

$$

= 50.5369 + 4.818 - 0.4171 + 2.324 - 0.3464 + 0.265 - 0.5335 + 0.0065

$$

Support Vector Regression

For this section of the analysis, linear and radial basis functions will be fit using support vector regression and an ordinary least squares regression model will be fit using step-wise variable selection.

cyber <- read.csv('https://raw.githubusercontent.com/GabbyK8/Datasets/refs/heads/main/Global_Cybersecurity_Threats_2015-2024.csv')

#One-Hot Encoding
dummy <- dummyVars("~.", data=cyber)
cyber2<-data.frame(predict(dummy, newdata=cyber))

#####
# Split data into features (X) and target (y)
X <- cyber2[, -25]  # All columns except the target variable
y <- cyber2[, 25]   # Target variable (Financial Loss in Millions)

# create dummy variables



#####
# Split data into training and testing sets
set.seed(123)
train.index <- sample(1:nrow(cyber2), 0.8 * nrow(cyber2))
X.train <- X[train.index, ]
y.train <- y[train.index]
X.test <- X[-train.index, ]
y.test <- y[-train.index]

#####
cyber2.train <- as.data.frame(cyber2[train.index, ])
cyber2.test <- cyber2[-train.index, ]
#####
## Set up custom cross-validation control
my_tune_control <- tune.control(
  cross = 5,  # Use 5-fold cross-validation, the default is 10-fold cross-validation
  nrepeat = 1 # Number of repetitions (for repeated cross-validation)
)
#####
# Perform grid search for hyperparameter tuning: RBF kernel is used
tune.RBF <- tune(svm,
                 train.x = X.train, 
                 train.y = y.train, 
                    ranges = list(epsilon = seq(0.1, 0.5, 0.1), 
                                  cost = c(1, 10, 100), 
                                  gamma = c(0.01, 0.1, 1)), # Hyperpar in RBF
                    tunecontrol = my_tune_control    # 5-fold cross-validation

                                    )

####
# Display the best parameters
#print(tune.RBF$best.parameters)
#####
# Train the final model using the best parameters
final.RBF<- svm(X.train, y.train, 
                   type = "eps-regression",  # Use "nu-regression" for nu-SVR
                   kernel = "radial", 
                   epsilon = tune.RBF$best.parameters$epsilon, 
                   cost = tune.RBF$best.parameters$cost, 
                   gamma = tune.RBF$best.parameters$gamma)
#####
# Make predictions on the test set
pred.RBF <- predict(final.RBF, X.test)

# Evaluate performance
mse.RBF <- mean((y.test - pred.RBF)^2)    # mean square error
mae.RBF <- mean(abs(y.test - pred.RBF))   # mean absolute error

#### linear kernel

# Perform grid search for hyperparameter tuning: RBF kernel is used
tune.lin <- tune(svm, train.x = X.train, train.y = y.train, 
                    ranges = list(epsilon = seq(0.1, 0.5, 0.1), 
                                  cost = c(1, 10, 100)), 
                    tunecontrol = my_tune_control # 5-fold cross-validation
                    )
####
# Display the best parameters
#print(tune.lin$best.parameters)
#####
# Train the final model using the best parameters
final.lin<- svm(X.train, y.train, 
                   type = "eps-regression",  # Use "nu-regression" for nu-SVR
                   kernel = "linear", 
                   epsilon = tune.lin$best.parameters$epsilon, 
                   cost = tune.lin$best.parameters$cost)
#####
# Make predictions on the test set
pred.lin <- predict(final.lin, X.test)

# Evaluate performance
mse.lin <- mean((y.test - pred.lin)^2)    # mean square error
mae.lin <- mean(abs(y.test - pred.lin))


RBF <- tune.RBF$best.parameters
Linear <- tune.lin$best.parameters
pander(RBF, caption='RBF Best Parameters')
RBF Best Parameters
  epsilon cost gamma
35 0.5 1 1
pander(Linear, caption='Linear SVR Best Parameters')
Linear SVR Best Parameters
  epsilon cost
5 0.5 1

The tables above show the fine tuned best parameters for both support vector regression models.

## ordinary LSE regression model with stepwise variable selection
lse.fit <- lm(Financial.Loss..in.Million...~.,data=cyber2.train)
AIC.fit <- stepAIC(lse.fit,direction="both", trace = FALSE)
pred.lse <- predict(AIC.fit, X.test)
mse.lse <- mean((y.test - pred.lse)^2)    # mean square error
mae.lse <- mean(abs(y.test - pred.lse))   # mean absolute error
###
par(mfrow=c(2,2), mar=c(2,2,2,2))
plot(AIC.fit)
The plots are a diagnostic plot for the least squares regression model.

The plots are a diagnostic plot for the least squares regression model.

The model above satisfies the linear regression assumptions and will be used to help compare performance.

Comparing Regression Models

In this section we will look at the performance of our least squares regression model after stepwise variable selection with our linear and radial basis function models from support vector regression.We will compare the model using MSE and MAE values.

###
Performance <- data.frame(RBF.SVR=c(mse.RBF, mae.RBF),
                          Linear.SVR = c(mse.lin, mae.lin),
                          LSE.Reg =c(mse.lse, mae.lse))
row.names(Performance) <- c("MSE", "MAE")
##
pander(Performance)
  RBF.SVR Linear.SVR LSE.Reg
MSE 811.8 829.2 810.4
MAE 24.54 24.75 24.45

The linear and least squares model performed better than the radial basis function model. The two models performed similarly, but the least squares model performed slightly better and will be chosen as the best model for the data.

Conclusion for Support Vector Regression

Based on our MSE and MAE scores, our least squares estimation has the best model based on performance in comparison to support vector regression on linear and radial basis function. It has lower MSE and MAE scores indicating a better fit model. Our final best model is:

\[ \text{Financial Loss in Millions} = 51.27 + 4.818\times \text{CountryGermany} - 3.525\times \text{CountryIndia} - 2.324\times \text{AttackSourceInsider} \]

LS0tCnRpdGxlOiAiUmVndWxhcml6ZWQgUmVncmVzc2lvbiBNb2RlbGluZyBvbiBGaW5hbmNpYWwgTG9zcyBkdWUgdG8gQ3liZXIgVGhyZWF0cyIKYXV0aG9yOiAiR2FicmllbGxhIEtoYWxpbCIKZGF0ZTogIjIwMjUtMDMtMjYiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIHRvY19mbG9hdDogeWVzCiAgICBudW1iZXJfc2VjdGlvbnM6IG5vCiAgICB0b2NfY29sbGFwc2VkOiB5ZXMKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgY29kZV9kb3dubG9hZDogeWVzCiAgICBzbW9vdGhfc2Nyb2xsOiB5ZXMKICAgIHRoZW1lOiBsdW1lbgogIHdvcmRfZG9jdW1lbnQ6IAogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNAogICAgZmlnX2NhcHRpb246IHllcwogICAga2VlcF9tZDogeWVzCiAgcGRmX2RvY3VtZW50OiAKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDQKICAgIGZpZ19jYXB0aW9uOiB5ZXMKICAgIG51bWJlcl9zZWN0aW9uczogbm8KICAgIGZpZ193aWR0aDogMwogICAgZmlnX2hlaWdodDogMwplZGl0b3Jfb3B0aW9uczogCiAgY2h1bmtfb3V0cHV0X3R5cGU6IGlubGluZQotLS0KCmBgYHs9aHRtbH0KCjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+CgovKiBDYXNjYWRpbmcgU3R5bGUgU2hlZXRzIChDU1MpIGlzIGEgc3R5bGVzaGVldCBsYW5ndWFnZSB1c2VkIHRvIGRlc2NyaWJlIHRoZSBwcmVzZW50YXRpb24gb2YgYSBkb2N1bWVudCB3cml0dGVuIGluIEhUTUwgb3IgWE1MLiBpdCBpcyBhIHNpbXBsZSBtZWNoYW5pc20gZm9yIGFkZGluZyBzdHlsZSAoZS5nLiwgZm9udHMsIGNvbG9ycywgc3BhY2luZykgdG8gV2ViIGRvY3VtZW50cy4gKi8KCmgxLnRpdGxlIHsgIC8qIFRpdGxlIC0gZm9udCBzcGVjaWZpY2F0aW9ucyBvZiB0aGUgcmVwb3J0IHRpdGxlICovCiAgZm9udC1zaXplOiAyMnB4OwogIGZvbnQtd2VpZ2h0OiBib2xkOwogIGNvbG9yOiBEYXJrUmVkOwogIHRleHQtYWxpZ246IGNlbnRlcjsKICBmb250LWZhbWlseTogIkdpbGwgU2FucyIsIHNhbnMtc2VyaWY7Cn0KaDQuYXV0aG9yIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBhdXRob3JzICAqLwogIGZvbnQtc2l6ZTogMThweDsKICBmb250LXdlaWdodDogYm9sZDsKICBmb250LWZhbWlseTogc3lzdGVtLXVpOwogIGNvbG9yOiBuYXZ5OwogIHRleHQtYWxpZ246IGNlbnRlcjsKfQpoNC5kYXRlIHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciB0aGUgZGF0ZSAgKi8KICBmb250LXNpemU6IDE4cHg7CiAgZm9udC1mYW1pbHk6IHN5c3RlbS11aTsKICBjb2xvcjogRGFya0JsdWU7CiAgdGV4dC1hbGlnbjogY2VudGVyOwogIGZvbnQtd2VpZ2h0OiBib2xkOwp9CmgxIHsgLyogSGVhZGVyIDEgLSBmb250IHNwZWNpZmljYXRpb25zIGZvciBsZXZlbCAxIHNlY3Rpb24gdGl0bGUgICovCiAgICBmb250LXNpemU6IDIycHg7CiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsKICAgIGNvbG9yOiBuYXZ5OwogICAgdGV4dC1hbGlnbjogY2VudGVyOwogICAgZm9udC13ZWlnaHQ6IGJvbGQ7Cn0KaDIgeyAvKiBIZWFkZXIgMiAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgZm9yIGxldmVsIDIgc2VjdGlvbiB0aXRsZSAqLwogICAgZm9udC1zaXplOiAyMHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7CiAgICBmb250LXdlaWdodDogYm9sZDsKfQoKaDMgeyAvKiBIZWFkZXIgMyAtIGZvbnQgc3BlY2lmaWNhdGlvbnMgb2YgbGV2ZWwgMyBzZWN0aW9uIHRpdGxlICAqLwogICAgZm9udC1zaXplOiAxOHB4OwogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7CiAgICBjb2xvcjogbmF2eTsKICAgIHRleHQtYWxpZ246IGxlZnQ7Cn0KCmg0IHsgLyogSGVhZGVyIDQgLSBmb250IHNwZWNpZmljYXRpb25zIG9mIGxldmVsIDQgc2VjdGlvbiB0aXRsZSAgKi8KICAgIGZvbnQtc2l6ZTogMThweDsKICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOwogICAgY29sb3I6IGRhcmtyZWQ7CiAgICB0ZXh0LWFsaWduOiBsZWZ0Owp9Cgpib2R5IHsgYmFja2dyb3VuZC1jb2xvcjp3aGl0ZTsgfQoKLmhpZ2hsaWdodG1lIHsgYmFja2dyb3VuZC1jb2xvcjp5ZWxsb3c7IH0KCnAgeyBiYWNrZ3JvdW5kLWNvbG9yOndoaXRlOyB9Cgo8L3N0eWxlPgpgYGAKCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgCiMgd2lsbCBiZSBpbmNsdWRlZCBpbiB0aGUgb3V0cHV0IGZpbGVzLgppZiAoIXJlcXVpcmUoImtuaXRyIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQogICBsaWJyYXJ5KGtuaXRyKQp9CmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsKICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikKbGlicmFyeSh0aWR5dmVyc2UpCn0KaWYgKCFyZXF1aXJlKCJHR2FsbHkiKSkgewogICBpbnN0YWxsLnBhY2thZ2VzKCJHR2FsbHkiKQpsaWJyYXJ5KEdHYWxseSkKfQoKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KHBhbmRlcikKbGlicmFyeShtb21lbnRzKQpsaWJyYXJ5KGNhcmV0KQpsaWJyYXJ5KGdsbW5ldCkKIyBHZW5lcmFsCmxpYnJhcnkoZTEwNzEpICAgICAgICAjIEZvciBTVk0gICAgICAgIyBGb3IgUmlkZ2UsIExhc3NvLCBsb2dpc3RpYyByZWdyZXNzaW9uCmxpYnJhcnkocFJPQykgICAgICAgICAjIEZvciBST0MgY3VydmVzCmxpYnJhcnkoTWV0cmljcykgICAgICAjIEZvciBNU0UvTUFFCmxpYnJhcnkoTUFTUykKIyBPcHRpb25hbCB2aXN1YWxpemF0aW9uCmxpYnJhcnkoZ3JpZEV4dHJhKQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUsICAgIyBpbmNsdWRlIGNvZGUgY2h1bmsgaW4gdGhlIG91dHB1dCBmaWxlCiAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsIyBzb21ldGltZXMsIHlvdSBjb2RlIG1heSBwcm9kdWNlIHdhcm5pbmcgbWVzc2FnZXMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB5b3UgY2FuIGNob29zZSB0byBpbmNsdWRlIHRoZSB3YXJuaW5nIG1lc3NhZ2VzIGluCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0aGUgb3V0cHV0IGZpbGUuIAogICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IFRSVUUsICMgeW91IGNhbiBhbHNvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgdGhlIG91dHB1dAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgaW4gdGhlIG91dHB1dCBmaWxlLgogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgY29tbWVudCA9IE5BCiAgICAgICAgICAgICAgICAgICAgICApICAKCmBgYAoKIyBBbmFseXNpcyBvZiBDeWJlci1zZWN1cml0eSBUaHJlYXRzCgojIyBBYnN0cmFjdAoKVGhlIHB1cnBvc2Ugb2YgdGhpcyBkYXRhIGFuYWx5c2lzIHdhcyB0byBmaW5kIHRoZSBtb3N0IGVmZmljaWVudCBtb2RlbCBmb3IgcHJlZGljdGluZyBmaW5hbmNpYWwgbG9zcyBkdWUgdG8gY3liZXIgc2VjdXJpdHkgYXR0YWNrcy4gQ3liZXIgc2VjdXJpdHkgYXR0YWNrcyBlZmZlY3QgYSBudW1iZXIgb2YgZGlmZmVyZW50IHR5cGVzIG9mIGluZHVzdHJpZXMgYW5kIGNhbiBiZSBoYXJtZnVsIG5vdCBvbmx5IHRvIHRoZSBwcml2YWN5IG9mIHRoZSBjb21wYW55LCBidXQgY2FuIGFsc28gY29udHJpYnV0ZSB0byBjb21wYW55IGxvc3Nlcy4gVGhpcyBhbmFseXNpcyB3aWxsIGV4cGxvcmUgTEFTU08sIFJpZGdlIGFuZCBFbGFzdGljIE5ldCBsaW5lYXIgcmVncmVzc2lvbiB0byBmaW5kIGFuIG9wdGltYWwgbW9kZWwgaW4gcHJlZGljdGluZyBmaW5hbmNpYWwgbG9zcy4gSXQgd2lsbCBhbHNvIGV4cGxvcmUgc3VwcG9ydCB2ZWN0b3IgcmVncmVzc2lvbiB0byBmaXQgdGhlIGRhdGEgdG8gYSBjZXJ0YWluIG1hcmdpbiBvZiBlcnJvciBhbmQgbWluaW1pemUgY29tcGxleGl0eSBvZiB0aGUgbW9kZWwuCgojIyBJbnRyb2R1Y3Rpb24KCkhvdyBtdWNoIG1vbmV5IGNhbiBiZSBsb3N0IGluIGEgc2luZ2xlIGN5YmVyIHNlY3VyaXR5IHRocmVhdD8gQnkgbW9kZWxpbmcgYW5kIG9ic2VydmluZyB0cmVuZHMgaW4gY3liZXIgc2VjdXJpdHkgdGhyZWF0IGRhdGEsIHRoaXMgYW5hbHlzaXMgc2Vla3MgdG8gaGVscCByZWR1Y2UgdGhlIGZpbmFuY2lhbCBpbXBhY3Qgb2YgY3liZXIgc2VjdXJpdHkgdGhyZWF0cy4gTGltaXRhdGlvbnMgb2YgdGhpcyBhbmFseXNpcyBpbmNsdWRlIHVuZGVyIHJlcG9ydGluZyBhbmQgZGF0YSBiaWFzLiBNYW55IG9yZ2FuaXphdGlvbnMgd2lsbCBub3QgcmVwb3J0IHNlY3VyaXR5IGJyZWFjaGVzIHB1YmxpY2x5IHRvIGF2b2lkIGRhbWFnZSB0byB0aGVpciByZXB1dGF0aW9uLiBBcyB3ZWxsLCB0aHJlYXRzIGNhbiBldm9sdmUgcXVpY2tseSwgbGVhZGluZyB0byBtb2RlbHMgYmVjb21pbmcgb3V0ZGF0ZWQgcmFwaWRseS4KCiMjIE92ZXJ2aWV3IG9mIERhdGEKClRoZSBkYXRhc2V0IHdhcyBvYnRhaW5lZCBmcm9tIEthZ2dsZSBhbmQgY29udGFpbnMgMTAgdmFyaWFibGVzIHRoYXQgYXJlIHBvdGVudGlhbCBzaWduaWZpY2FudCBjb3ZhcmlhdGVzIGluIHByZWRpY3RpbmcgcG90ZW50aWFsIHRocmVhdHMuIFRoZSB2YXJpYWJsZSBjb3VudHJ5IHJlZmVycyB0byB0aGUgY291bnRyeSB3aGVyZSB0aGUgYXR0YWNrIG9jY3VycmVkLiBUaGUgb3RoZXIgdmFyaWFibGVzIGFuYWx5emUgaW5jaWRlbnQgcmVzb2x1dGlvbiB0aW1lIGluIGhvdXJzLCBudW1iZXIgb2YgYWZmZWN0ZWQgdXNlcnMsIGZpbmFuY2lhbCBsb3NzLCBhdHRhY2sgdHlwZSwgdGFyZ2V0IGluZHVzdHJ5LCBhdHRhY2sgc291cmNlLCBzZWN1cml0eSB2dWxuZXJhYmlsaXR5IHR5cGUgYW5kIGRlZmVuc2UgbWVjaGFuaXNtIHVzZWQuIEhlcmUgaXMgYSBmdWxsIGxpc3Qgb2YgdmFyaWFibGVzOgoKLSAgICoqQ291bnRyeSoqIGNvdW50cnkgd2hlcmUgdGhlIGF0dGFjayBvY2N1cnJlZAotICAgKipZZWFyKiogeWVhciBvZiB0aGUgaW5jaWRlbnQKLSAgICoqQXR0YWNrIFR5cGUqKiB0eXBlIG9mIGN5YmVyLXNlY3VyaXR5IHRocmVhdAotICAgKipUYXJnZXQgSW5kdXN0cnkqKiBpbmR1c3RyeSB0YXJnZXRlZAotICAgKipGaW5hbmNpYWwgTG9zcyoqIGVzdGltYXRlZCBmaW5hbmNpYWwgbG9zcyBpbiBtaWxsaW9ucwotICAgKipOdW1iZXIgb2YgQWZmZWN0ZWQgVXNlcnMqKiBudW1iZXIgb2YgdXNlcnMgaW1wYWN0ZWQgYnkgdGhlIGF0dGFjawotICAgKipBdHRhY2sgU291cmNlKiogb3JpZ2luIG9mIHRoZSBhdHRhY2sKLSAgICoqU2VjdXJpdHkgVnVsbmVyYWJpbGl0eSBUeXBlKiogdHlwZSBvZiB2dWxuZXJhYmlsaXR5IGV4cGxvaXRlZAotICAgKipEZWZlbnNlIE1lY2hhbmlzbSBVc2VkKiogY3liZXItc2VjdXJpdHkgZGVmZW5zZSBzdHJhdGVneSBhcHBsaWVkCi0gICAqKkluY2lkZW50IFJlc29sdXRpb24gVGltZSoqIHRpbWUgdGFrZW4gdG8gZnVsbHkgcmVzb2x2ZSBldmVudCBpbiBob3VycwoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGlzIHBsb3Qgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNlY3VyaXR5IHZ1bG5lcmFiaWxpdHkgdHlwZSBhbmQgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gdGhlIG51bWJlciBvZiBhZmZlY3RlZCB1c2VycyBhbmQgZmluYW5jaWFsIGxvc3MgaW4gbWlsbGlvbnMuIEluIG1vc3QgY2FzZXMgdGhlIG51bWJlciBvZiBhZmZlY3RlZCB1c2VycyBzZWVtcyB0byBiZSBwb3NpdGl2ZWx5IGNvcnJlbGF0ZWQgd2l0aCBmaW5hbmNpYWwgbG9zcy4gVGhlIG9ubHkgZXhjZXB0aW9uIGlzIHNlZW4gaW4gemVyby1kYXkuIHplcm8tZGF5IHJlZmVycyB0byBhIHR5cGUgb2YgdnVsbmVyYWJpbGl0eSB3aGVyZSB0aGUgdGFyZ2V0IG9mIHRoZSBhdHRhY2sgaXMgdW5hd2FyZSBvZiB0aGUgYXR0YWNrLiBNZWFuaW5nIHRoZXJlIGFyZSB6ZXJvIGRheXMgZm9yIHRoZSBwcm9ibGVtIHRvIGJlIHNvbHZlZCBiZWZvcmUgaXQgaGFzIGJlZW4gZXhwbG9pdGVkLiBJdCB3b3VsZCBtYWtlIHNlbnNlIHRoYXQgaW4gdGhpcyB0eXBlIG9mIHZ1bG5lcmFiaWxpdHksIHRoZSBmZXdlciB1c2VycyBhZmZlY3RlZCB3b3VsZCBsZWFkIHRvIGEgZ3JlYXRlciBmaW5hbmNpYWwgbG9zcy4nfQpjeWJlciA8LSByZWFkLmNzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL0dhYmJ5SzgvRGF0YXNldHMvcmVmcy9oZWFkcy9tYWluL0dsb2JhbF9DeWJlcnNlY3VyaXR5X1RocmVhdHNfMjAxNS0yMDI0LmNzdicpCmN5YmVyJERlZmVuc2UuTWVjaGFuaXNtLlVzZWQgPC0gaWZlbHNlKGN5YmVyJERlZmVuc2UuTWVjaGFuaXNtLlVzZWQgPT0gIkFJLWJhc2VkIERldGVjdGlvbiIsICJBSSIsIGN5YmVyJERlZmVuc2UuTWVjaGFuaXNtLlVzZWQpCgojIHBsb3QgMSBudW1iZXIgb2YgYWZmZWN0ZWQgdXNlcnMgYnkgZmluYW5jaWFsIGxvc3MgYnkgdnVsbmVyYWJpbGl0eSB0eXBlCgoKZ2dwbG90KGN5YmVyLCBhZXMoeCA9IGN5YmVyJE51bWJlci5vZi5BZmZlY3RlZC5Vc2VycywgeSA9IGN5YmVyJEZpbmFuY2lhbC5Mb3NzLi5pbi5NaWxsaW9uLi4uLCBjb2xvciA9IGN5YmVyJFNlY3VyaXR5LlZ1bG5lcmFiaWxpdHkuVHlwZSkpICsKZ2VvbV9zbW9vdGgoYWVzKHggPSBjeWJlciROdW1iZXIub2YuQWZmZWN0ZWQuVXNlcnMsIHkgPSBjeWJlciRGaW5hbmNpYWwuTG9zcy4uaW4uTWlsbGlvbi4uLiwgY29sb3IgPSBjeWJlciRTZWN1cml0eS5WdWxuZXJhYmlsaXR5LlR5cGUpLCBtZXRob2QgPSAibG0iLCBzZSA9IEZBTFNFKSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMiwgMTApKSArCiAgbGFicygKICAgIHRpdGxlID0gIlBsb3Qgb2YgU2VjdXJpdHkgVnVsbmVyYWJpbGl0eSwgVm9sdW1lIENvbXByb21pc2VkLCBhbmQgRmluYW5jaWFsIEltcGFjdCIsCiAgICB4ID0gIlZvbHVtZSBDb21wcm9taXNlZCIsCiAgICB5ID0gIkZpbmFuY2lhbCBJbXBhY3QiLAogICAgY29sb3IgPSAiU2VjdXJpdHkgVnVsZXJuYWJpbGl0eSIKICApICsKICB0aGVtZV9taW5pbWFsKCkKYGBgCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoaXMgcGxvdCBzaG93cyB0aGUgZGVuc2l0eSBvZiBudW1iZXIgb2YgYWZmZWN0ZWQgdXNlcnMgaW4gY3liZXJzZWN1cml0eSBhdHRhY2tzIGluIGVhY2ggY291bnRyeSBpbiB0aGUgeWVhciAyMDE1LiAnfQojIHBsb3QgMyBEZW5zaXR5IHBsb3Qgb2YgYXR0YWNrZWQgaW5kdXN0cmllcwpZZWFyX2RhdGEgPC0gY3liZXIgJT4lCiAgZmlsdGVyKFllYXIgPT0gMjAxNSkKcDE8LSBnZ3Bsb3QoWWVhcl9kYXRhLCBhZXMoeCA9IE51bWJlci5vZi5BZmZlY3RlZC5Vc2VycywgZmlsbCA9IENvdW50cnkpKSArCiAgZ2VvbV9kZW5zaXR5KGFscGhhID0gMC42KSArCiAgbGFicygKICAgIHggPSAiTnVtYmVyIG9mIEFmZmVjdGVkIFVzZXJzIiwKICAgIHkgPSAiRGVuc2l0eSIsCiAgICBmaWxsPSJDb3VudHJ5IiwKICAgIHRpdGxlID0gIkRlbnNpdHkgUGxvdCBvZiBBdHRhY2tlZCBDb3VudHJpZXMgaW4gMjAxNSIKICApICsKICB0aGVtZV9taW5pbWFsKCkKZ2dwbG90bHkocDEpCmBgYAoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSJUaGlzIHBsb3Qgc2hvd3MgdGhlIGRlbnNpdHkgb2YgbnVtYmVyIG9mIGFmZmVjdGVkIHVzZXJzIGluIGN5YmVyc2VjdXJpdHkgYXR0YWNrcyBpbiBlYWNoIGNvdW50cnkgaW4gdGhlIHllYXIgMjAyNC4gIn0KIFllYXJfZGF0YTEgPC0gY3liZXIgJT4lCiAgZmlsdGVyKFllYXIgPT0gMjAyNCkKIyBwbG90IDQgRGVuc2l0eSBwbG90IG9mIEF0dGFja2VkIGNvdW50cmllcwpwMiA8LSBnZ3Bsb3QoWWVhcl9kYXRhMSwgYWVzKHggPSBOdW1iZXIub2YuQWZmZWN0ZWQuVXNlcnMsIGZpbGwgPSBDb3VudHJ5KSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IDAuNikgKwogIGxhYnMoCiAgICB4ID0gIk51bWJlciBvZiBBZmZlY3RlZCBVc2VycyIsCiAgICB5ID0gIkRlbnNpdHkiLAogICAgZmlsbD0iQ291bnRyeSIsCiAgICB0aXRsZSA9ICJEZW5zaXR5IFBsb3Qgb2YgQXR0YWNrZWQgQ291bnRyaWVzIGluIDIwMjQiCiAgKSArCiAgdGhlbWVfbWluaW1hbCgpCmdncGxvdGx5KHAyKQoKYGBgCgpFYWNoIGNvdW50cnkgaXMgZ2l2ZW4gYSBzcGVjaWZpYyBjb2xvciBhbmQgdGhlIG51bWJlciBvZiBhZmZlY3RlZCB1c2VycyBpcyBkaXNwbGF5ZWQgb24gdGhlIHgtYXhpcy4gVGhlIGRlbnNpdHkgaXMgZGlzcGxheWVkIG9uIHRoZSB5LWF4aXMuIERlbnNpdHkgaW4gdGhpcyBwbG90IHNob3dzIHRoZSByZWxhdGl2ZSBmcmVxdWVuY3kgb2YgbnVtYmVyIG9mIGFmZmVjdGVkIHVzZXJzIHBlciBhdHRhY2sgaW4gZWFjaCBjb3VudHJ5LkluIDIwMTUsIHRoZSBjeWJlciBhdHRhY2tzIHdpdGhpbiB0aGUgVVNBIG1vcmUgZnJlcXVlbnRseSBhZmZlY3RlZCBhYm91dCAzMTAsMDAwIHVzZXJzLCBjb21wYXJlZCB0byBSdXNzaWEgd2hlcmUgYXR0YWNrcyBtb3JlIGZyZXF1ZW50bHkgYXR0YWNrZWQgNjcwLDAwMCB1c2VycyBhbmQgR2VybWFueSB3aGVyZSBtb3N0IGF0dGFja3MgbW9yZSBmcmVxdWVudGx5IGFmZmVjdGVkIDc5MCwwMDAgdXNlcnMuIEluIDIwMjQsIHRoZSBudW1iZXIgb2YgYWZmZWN0ZWQgdXNlcnMgaW4gdGhlIFVTQSBkb2VzIG5vdCBzZWVtIHRvIGJlIG11Y2ggbW9yZSBkZW5zZSBpbiBhbnkgb25lIG51bWJlciBhbmQgaXMgbW9yZSBkaXNwZXJzZWQuIEphcGFuIGhhZCBtb3JlIGZyZXF1ZW50IGF0dGFja3MgdGhhdCBhZmZlY3RlZCA1MDAsMDAwIGFuZCBCcmF6aWwgaGFkIGl0J3MgbW9zdCBmcmVxdWVudCBhdCA3NTAsMDAwIHVzZXJzLgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGlzIHBsb3Qgc2hvd3MgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHNlY3VyaXR5IHZ1bG5lcmFiaWxpdHkgdHlwZSBhbmQgdGhlIGludGVyYWN0aW9uIGJldHdlZW4gdGhlIHllYXIgb2YgYXR0YWNrIGFuZCByZXNvbHV0aW9uIHRpbWUuIFRoZSBwbG90IHNob3dzIGhvdyBvdmVyIHRoZSB5ZWFycyByZXNvbHV0aW9uIHRpbWUgaGFzIGltcHJvdmVkIGZvciBjZXJ0YWluIHZ1bG5lcmFiaWxpdHkgdHlwZXMsIHN1Y2ggYXMgd2VhayBwYXNzd29yZHMsIHVucGF0Y2hlZCBzb2Z0d2FyZSwgYW5kIHNvY2lhbCBlbmdpbmVlcmluZy4gSG93ZXZlciwgZm9yIHplcm8tZGF5IHRoZXJlIGlzIGFuIGluY3JlYXNlIGluIHJlc29sdXRpb24gdGltZSwgc2hvd2luZyBhIHBvc2l0aXZlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIHplcm8tZGF5IGFuZCByZXNvbHV0aW9uIHRpbWUuICd9CgpnZ3Bsb3QoY3liZXIsIGFlcyh4ID0gY3liZXIkWWVhciwgeSA9IGN5YmVyJEluY2lkZW50LlJlc29sdXRpb24uVGltZS4uaW4uSG91cnMuLCBjb2xvciA9IGN5YmVyJFNlY3VyaXR5LlZ1bG5lcmFiaWxpdHkuVHlwZSkpICsKZ2VvbV9zbW9vdGgoYWVzKHggPSBjeWJlciRZZWFyLCB5ID0gY3liZXIkSW5jaWRlbnQuUmVzb2x1dGlvbi5UaW1lLi5pbi5Ib3Vycy4sIGNvbG9yID0gY3liZXIkU2VjdXJpdHkuVnVsbmVyYWJpbGl0eS5UeXBlKSwgbWV0aG9kID0gImxtIiwgc2UgPSBGQUxTRSkgKwogIHNjYWxlX3NpemUocmFuZ2UgPSBjKDIsIDEwKSkgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJQbG90IG9mIFNlY3VyaXR5IFZ1bG5lcmFiaWxpdHksIFllYXIgb2YgQXR0YWNrLCBhbmQgUmVzb2x1dGlvbiBUaW1lIiwKICAgIHggPSAiWWVhciBvZiBBdHRhY2siLAogICAgeSA9ICJJbmNpZGVudCBSZXNvbHV0aW9uIFRpbWUgaW4gSG91cnMiLAogICAgY29sb3IgPSAiU2VjdXJpdHkgVnVsZXJuYWJpbGl0eSIKICApICsKICB0aGVtZV9taW5pbWFsKCkKCmBgYAoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGlzIHBsb3QgZm9jdXNlcyBvbiB6ZXJvLWRheSB2dWxuZXJhYmlsaXR5IGFuZCBzaG93cyB0aGUgcHJvcG9ydGlvbiBvZiB0aHJlYXQgdHlwZXMgaW4gZWFjaCBpbmR1c3RyeS4gVGhlIHgtYXhpcyBzaG93cyBlYWNoIHRocmVhdCB0eXBlIGFuZCB0aGUgeS1heGlzIHNob3dzIHRoZSBwcm9wb3J0aW9uIG9mIGF0dGFja3Mgd2l0aGluIHRoZSBkYXRhc2V0IHRoYXQgZmFsbCBpbnRvIGVhY2ggY2F0ZWdvcnkuIFRoZSBkaWZmZXJlbnQgY29sb3JzIGFyZSBtZWFudCB0byBzaG93IGEgc3ViY2F0ZWdvcnksIHRhcmdldCBpbmR1c3RyeS4gVGhpcyBzaG93cyB0aGUgcHJvcG9ydGlvbiBvZiB0aGUgZGF0YXNldCB0aGF0IGZhbGxzIHdpdGhpbiBlYWNoIGNhdGVnb3J5IG9mIHRocmVhdCB0eXBlIGluIGVhY2ggdGFyZ2V0IGluZHVzdHJ5Lid9CiNwbG90IG9mIHplcm8tZGF5IGF0dGFjayB0eXBlIGJ5IHRhcmdldCBpbmR1c3RyeQp6ZXJvX2RhdGEgPC0gY3liZXIgJT4lCiAgZmlsdGVyKFNlY3VyaXR5LlZ1bG5lcmFiaWxpdHkuVHlwZSA9PSAiWmVyby1kYXkiKSAKYSA8LSBnZ3Bsb3QoemVyb19kYXRhLCBhZXMoeCA9IHplcm9fZGF0YSRBdHRhY2suVHlwZSwgZmlsbCA9emVyb19kYXRhJFRhcmdldC5JbmR1c3RyeSApKSArCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZG9kZ2UiKSArCiAgbGFicygKICAgIHggPSAiVGhyZWF0IFR5cGUiLAogICAgeSA9ICJQcm9wb3J0aW9uIiwKICAgIGZpbGwgPSAiVGFyZ2V0IEluZHVzdHJ5IiwKICAgIHRpdGxlID0gIlplcm8tZGF5IEluY2lkZW5jZXMgYnkgVGhyZWF0IFR5cGUgdnMuIFRhcmdldCBJbmR1c3RyeSIKICApICsKICB0aGVtZV9taW5pbWFsKCkKZ2dwbG90bHkoYSkKYGBgCgpaZXJvLWRheSBhdHRhY2tzIHNlZW0gdG8gY29tbW9ubHkgdXNlIFBoaXNpbmcgd2l0aGluIGJvdGggcmV0YWlsIGFuZCBJVCBpbmR1c3RyaWVzLCBiYXNlZCBvbiB0aGUgaGVpZ2h0IGFuZCBjb3VudCBvZiB0aGUgYmFyIGluIHRoZXNlIHR3byBjYXRlZ29yaWVzLiBSYW5zb213YXJlIGlzIHRoZSBtb3N0IG1pbmltYWxseSB1c2VkIHplcm8tZGF5IGF0dGFjayBvbiB0aGUgZ292ZXJubWVudCwgd2l0aCBhIGNvdW50IG9mIGp1c3QgMTIuCgpgYGB7ciBmaWcuYWxpZ249J2NlbnRlcicsIGZpZy53aWR0aD03LCBmaWcuaGVpZ2h0PTUsIGZpZy5jYXA9J1RoZSBibG94cGxvdCBzaG93cyB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZGVmZW5zZSBtZWNoYW5pc20gYW5kIHJlc29sdXRpb24gdGltZSBpbiBob3Vycy4nfQoKY29sMD1jKCIjNDY4MkI0IiwgIiNCNDQ2NEIiLCIjOTkwMEZGIiwiI0ZGNjZGRiIsICIjMDA5OTMzIikKYm94cGxvdChJbmNpZGVudC5SZXNvbHV0aW9uLlRpbWUuLmluLkhvdXJzLiB+IERlZmVuc2UuTWVjaGFuaXNtLlVzZWQsCiAgICAgICAgZGF0YT1jeWJlciwKICAgICAgICB4bGFiPSJEZWZlbnNlIE1lY2hhbmlzbSIsCiAgICAgICAgeWxhYj0iUmVzb2x1dGlvbiBUaW1lIChob3VycykiLAogICAgICAgIGNvbCA9IGNvbDAsCiAgICAgICAgbWFpbj0iSW5jaWRlbnQgUmVzb2x1dGlvbiBUaW1lIGJ5IERlZmVuc2UgTWVjaGFuaXNtIiwKICAgICAgICBjZXgubWFpbiA9IDAuOSwKICAgICAgICBjb2wubWFpbiA9ICJibHVlIikKCgpgYGAKClRoZSBib3hwbG90IHNob3dzIHRoYXQgdGhlIGF2ZXJhZ2UgcmVzb2x1dGlvbiB0aW1lIGFtb25nIGF0dGFja3MgYmFzZWQgb24gZGVmZW5zZSBtZWNoYW5pc21zIGlzIHJlbGF0aXZlbHkgdGhlIHNhbWUuIFRoZSBvbmx5IGV4Y2VwdGlvbiBzZWVtcyB0byBiZSBmaXJld2FsbCwgd2hpY2ggYXBwZWFycyB0byB0YWtlIHNsaWdodGx5IGxlc3MgcmVzb2x1dGlvbiB0aW1lIG9uIGF2ZXJhZ2UuV2UgY2FuIGluZGljYXRlIHRoZSBhdmVyYWdlIGJ5IGxvb2tpbmcgdGhlIGJsYWNrIGhvcml6b250YWwgbGluZSB3aXRoaW4gZWFjaCBib3guIFRoZXkgYWxsIGFwcGVhciB0byBsaW5lIHVwIHdpdGggb25lIGFub3RoZXIgaW5kaWNhdGluZyBzaW1pbGFyIGF2ZXJhZ2VzLgoKIyMgU2tld25lc3MKCmBgYHtyfQoKY3liZXIkQ291bnRyeVtjeWJlciRDb3VudHJ5PT0iVVNBIl08LTEKY3liZXIkQ291bnRyeTwtIGlmZWxzZShjeWJlciRDb3VudHJ5IT0iVVNBIiwwKQpjeWJlciRTZWN1cml0eS5WdWxuZXJhYmlsaXR5LlR5cGVbY3liZXIkU2VjdXJpdHkuVnVsbmVyYWJpbGl0eS5UeXBlPT0iWmVyby1kYXkiXTwtMQpjeWJlciRTZWN1cml0eS5WdWxuZXJhYmlsaXR5LlR5cGU8LWlmZWxzZShjeWJlciRTZWN1cml0eS5WdWxuZXJhYmlsaXR5LlR5cGUhPSJaZXJvLWRheSIsMCkKY3liZXIkTnVtYmVyLm9mLkFmZmVjdGVkLlVzZXJzPC1hcy5udW1lcmljKGN5YmVyJE51bWJlci5vZi5BZmZlY3RlZC5Vc2VycykKY3liZXIkWWVhcjwtYXMubnVtZXJpYyhhcy5mYWN0b3IoY3liZXIkWWVhcikpCmN5YmVyJEluY2lkZW50LlJlc29sdXRpb24uVGltZS4uaW4uSG91cnMuPC1hcy5udW1lcmljKGN5YmVyJEluY2lkZW50LlJlc29sdXRpb24uVGltZS4uaW4uSG91cnMuKQoKCmM8LXNrZXduZXNzKGN5YmVyJEZpbmFuY2lhbC5Mb3NzLi5pbi5NaWxsaW9uLi4uKQpkPC1za2V3bmVzcyhjeWJlciROdW1iZXIub2YuQWZmZWN0ZWQuVXNlcnMpCmU8LXNrZXduZXNzKGN5YmVyJFllYXIpIAoKU2tld25lc3MgPSBjYmluZChGaW5hbmNpYWwuTG9zcyA9IGMsIAogICAgICAgICAgICAgICAgIEFmZmVjdGVkLlVzZXJzID0gIGQsIAogICAgICAgICAgICAgICAgIFllYXIgPSBlKQoKcGFuZGVyKFNrZXduZXNzKQpgYGAKClRoZSBkYXRhIGlzIG5vcm1hbGx5IHNrZXdlZCBhbmQgbm8gdHJhbnNmb3JtYXRpb24gaXMgbmVjZXNzYXJ5LgoKIyBSZWd1bGFyaXplZCBSZWdyZXNzaW9uIE1vZGVsaW5nCgpGb3IgdGhpcyBhbmFseXNpcywgd2Ugd2lsbCBleHBsb3JlIHRocmVlIHR5cGVzIG9mIHJlZ3VsYXJpemVkIGxpbmVhciByZWdyZXNzaW9uIG1vZGVsaW5nIHRvIGZpbmQga2V5IHByZWRpY3RvcnMgZm9yIGZpbmFuY2lhbCBsb3NzIGZyb20gY3liZXIgc2VjdXJpdHkgYXR0YWNrcy4KCmBgYHtyIGZpZy5hbGlnbj0nY2VudGVyJywgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEyLCBmaWcuY2FwPSdUaGUgeC1heGlzIG9mIHRoZSBjb2VmZmljaWVudCBwYXRoIGFuYWx5c2lzIHNob3dzIHRoZSBsb2cgb2YgbGFtYmRhLiBBIGxvdyBsYW1iZGEgaGFzIGxlc3MgcmVndWxhcml6YXRpb24gYW5kIGlzIGNsb3NlciB0byBvcmRpbmFyeSBsZWFzdCBzcXVhcmVzLiBBIGhpZ2ggbGFtYmRhIGluZGljYXRlcyBoaWdoZXIgcmVndWxhcml6YXRpb24gYW5kIGF0IHRoaXMgbGFtYmRhIG1hbnkgY29lZmZpY2llbnRzIHdpbGwgc2hyaW5rIHRvIHplcm8uIFRoZSBZLWF4aXMgc2hvd3MgdGhlIGNvZWZmaWNpZW50IHZhbHVlcyBmb3IgZWFjaCB2YXJpYWJsZSBwcmVkaWN0b3IgZm9yIGZpbmFuY2lhbCBsb3NzLiBUaGUgbGluZXMgc2hvd3MgdGhlIHBhdGggb2YgZWFjaCBjb2VmZmljaWVudCBoYXMgbGFtYmRhIGRpZmZlcnMuIFRoZSBkYXNoZWQgbGluZSBzaG93cyB0aGUgb3B0aW1hbCBsZXZlbCBvZiBzaHJpbmthZ2UuIENvZWZmaWNpZW50cyB0byB0aGUgcmlnaHQgb2YgdGhpcyBsaW5lIGFyZSBtb3JlIGZvcmNlZCB0b3dhcmRzIHplcm8uIEF0IHRoaXMgY2hvc2VuIGxhbWJkYSBvbmx5IGNlcnRhaW4gdmFyaWFibGVzIHdpbGwgYmUgbm9uLXplcm8gYW5kIGFyZSBkZWVtZWQgc2lnbmlmaWNhbnQuICd9CgoKCgojIFByZWRpY3RvcnMgKHgpIGFuZCBSZXNwb25zZSBWYXJpYWJsZSAoeSkKCnNldC5zZWVkKDEyMzQ1KQpYIDwtIGFzLmRhdGEuZnJhbWUoY3liZXJbLCAtNV0pICAKCnkgPC0gY3liZXIkRmluYW5jaWFsLkxvc3MuLmluLk1pbGxpb24uLi4KCgp0cmFpbl9pbmRleCA8LSBjcmVhdGVEYXRhUGFydGl0aW9uKHksIHAgPSAwLjgsIGxpc3QgPSBGQUxTRSkKWF90cmFpbiA8LSBtYWtlWChYW3RyYWluX2luZGV4LCBdKQpYX3Rlc3QgPC0gbWFrZVgoWFstdHJhaW5faW5kZXgsIF0pCnlfdHJhaW4gPC0geVt0cmFpbl9pbmRleF0KeV90ZXN0IDwtIHlbLXRyYWluX2luZGV4XQoKI3N0YW5kYXJkaXppbmcgdGhlIGRhdGEKcHJlcHJvY2Vzc19wYXJhbXMgPC0gcHJlUHJvY2VzcyhYX3RyYWluLCBtZXRob2QgPSBjKCJjZW50ZXIiLCJzY2FsZSIpKQpYX3RyYWluIDwtIHByZWRpY3QocHJlcHJvY2Vzc19wYXJhbXMsIFhfdHJhaW4pClhfdGVzdCA8LSBwcmVkaWN0KHByZXByb2Nlc3NfcGFyYW1zLCBYX3Rlc3QpCgoKI2ZpdHRpbmcgdGhlIG1vZGVsCmZpdF9sYXNzbyA8LSBnbG1uZXQoWF90cmFpbiwgeV90cmFpbiwgYWxwaGEgPSAxKSAgIyBMYXNzbwpmaXRfcmlkZ2UgPC0gZ2xtbmV0KFhfdHJhaW4sIHlfdHJhaW4sIGFscGhhID0gMCkgICMgUmlkZ2UKZml0X2VsYXN0aWNfbmV0IDwtIGdsbW5ldChYX3RyYWluLCB5X3RyYWluLCBhbHBoYSA9IDAuNSkgICMgRWxhc3RpYyBOZXQKI2Nyb3NzLXZhbGlkYXRpb24KY3ZfbGFzc28gPC0gY3YuZ2xtbmV0KFhfdHJhaW4sIHlfdHJhaW4sIGFscGhhID0gMSkgICAgICAgIyBMYXNzbyBDVgpjdl9yaWRnZSA8LSBjdi5nbG1uZXQoWF90cmFpbiwgeV90cmFpbiwgYWxwaGEgPSAwKSAgICAgICAjIFJpZGdlIENWCmN2X2VsYXN0aWNfbmV0IDwtIGN2LmdsbW5ldChYX3RyYWluLCB5X3RyYWluLCBhbHBoYSA9IDAuNSkgICMgRWxhc3RpYyBOZXQgQ1YKCiNwbG90IGNvZWZmaWNpZW50IHBhdGgKcGFyKG1hcj1jKDUsNCw2LDMpKQojIFBsb3QgY29lZmZpY2llbnQgcGF0aApwbG90KGZpdF9sYXNzbywgeHZhciA9ICJsYW1iZGEiLCBsYWJlbCA9IFRSVUUsCiAgICAgbHdkID0gMS41LAogICAgIG1haW4gPSAiQ29lZmZpY2llbnQgUGF0aCBBbmFseXNpczogTEFTU08iLAogICAgIGNleC5tYWluID0gMC45LAogICAgIGNvbCA9IHJhaW5ib3coMTApKQphYmxpbmUodiA9IGxvZygxKSwgY29sID0gInB1cnBsZSIsIGx0eSA9IDQsIGx3ZCA9IDIpCmFibGluZSh2ID0gLTEsIGNvbCA9ICJzdGVlbGJsdWUiLCBsdHkgPSAyLCBsd2QgPSAyKQoKYGBgCgpgYGB7cn0KCnBhbmRlcihkYXRhLmZyYW1lKGNvbG5hbWVzKFhfdHJhaW4pW2MoMjcsIDUsIDIwLCAxMildKSxjYXB0aW9uPSAiRmVhdHVyZSBWYXJpYWJsZXMgYXQgbG9nKExhbWJkYSkgPSAwIikKCnBhbmRlcihkYXRhLmZyYW1lKGNvbG5hbWVzKFhfdHJhaW4pW2MoMTgsIDEyLCAxMCwgMjQsIDUsIDIzLCAxNywgMTEsIDMpXSksY2FwdGlvbj0gIiBGZWF0dXJlIFZhcmlhYmxlcyBhdCBsb2coTGFtYmRhKSA9IC0xIikKYGBgCgpUaGUgdGFibGUgYWJvdmUgZGlzcGxheXMgdGhlIGZlYXR1cmUgdmFyaWFibGVzIG9ic2VydmVkIGluIHRoZSBDb2VmZmljaWVudCBBbmFseXNpcyBwbG90LgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdCBvZiBwZXJmb3JtYW5jZSBzaG93cyB0aGF0IGFzIGxhbWJkYSBpbmNyZWFzZXMsIHRoZSBNU0UgZGVjcmVhc2VzLiBUaGUgdHdvIHZlcnRpY2FsIGxpbmVzIGdpdmUgYSByZWZlcmVuY2Ugb2YgbGFtYmRhLiAnfQpwYXIobWFyPWMoNSw0LDYsMykpCiMjCnBsb3QoY3ZfbGFzc28sIG1haW4gPSAiUk1TRSBQbG90OiBMQVNTTyIsCiAgICAgY2V4Lm1haW4gPSAwLjkpCmBgYAoKYGBge3J9CiMgRXh0cmFjdCBjb2VmZmljaWVudHMgZm9yIHRoZSBiZXN0IGxhbWJkYQpiZXN0Lmxhc3NvLmxhbWJkYSA8LSBjdl9sYXNzbyRsYW1iZGEubWluCmJlc3QucmlkZ2UubGFtYmRhIDwtIGN2X3JpZGdlJGxhbWJkYS5taW4KYmVzdC5lbGFzdGljLm5ldC5sYW1iZGEgPC0gY3ZfZWxhc3RpY19uZXQkbGFtYmRhLm1pbgojIwojIExhc3NvIFJlZ3Jlc3Npb24gKEwxIFJlZ3VsYXJpemF0aW9uKTogCiMgQ0FVVElPTjogbW9kZWwgZm9ybXVsYSBkaWZmZXJzIGZyb20gdGhlIHJlZ3VsYXIgcmVncmVzc2lvbiBmb3JtdWxhIApsYXNzb19tb2RlbC5vcHQgPC0gZ2xtbmV0KFhfdHJhaW4sIAogICAgICAgICAgICAgICAgICAgICAgeV90cmFpbiwgCiAgICAgICAgICAgICAgICAgICAgICBhbHBoYSA9IDEsICAgICAgIyBsYXNzbyByZWdyZXNzaW9uIAogICAgICAgICAgICAgICAgICAgICAgbGFtYmRhID0gYmVzdC5sYXNzby5sYW1iZGEsc3RhbmRhcmRpemUgPSBUUlVFKSAgICMgdXNlc2VyIHNlbGVjdGVkIGFscGhhLCBvcHRpbWFsIGxhbWJkYQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNhbiBiZSBvYnRhaW5lZCB0aHJvdWdoIENWIChzZWUgYmVsb3cpCmxhc3NvX3ByZWRpY3Rpb25zLm9wdCA8LSBwcmVkaWN0KGxhc3NvX21vZGVsLm9wdCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcyA9IGJlc3QubGFzc28ubGFtYmRhLCAjIHVzZXIgc2VsZWN0ZWQgbGFtYmRhIHZhbHVlIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgKHJlZ3VsYXJpemF0aW9uIHBhcmVtZXRlcikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXd4ID0gWF90ZXN0KSAgIyB0ZXN0IGRhdGEgc2V0IAojIFRoZSBmb2xsb3dpbmcgUk1TRSBvZiBwcmVkaWN0aW9uIHNlcnZlcyBhcyBhIHZhbGlkYXRpb24gLSBvbmUgc3RlcCB2YWxpZGF0aW9uCmxhc3NvX3Jtc2Uub3B0IDwtIHNxcnQobWVhbigoeV90ZXN0IC0gbGFzc29fcHJlZGljdGlvbnMub3B0KV4yKSkgICAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiMgUmlkZ2UgUmVncmVzc2lvbiAoTDIgUmVndWxhcml6YXRpb24pCnJpZGdlX21vZGVsLm9wdCA8LSBnbG1uZXQoWF90cmFpbiwgeV90cmFpbiwgYWxwaGEgPSAwLCBsYW1iZGEgPSBiZXN0LnJpZGdlLmxhbWJkYSxzdGFuZGFyZGl6ZT1UUlVFKQpyaWRnZV9wcmVkaWN0aW9ucy5vcHQgPC0gcHJlZGljdChyaWRnZV9tb2RlbC5vcHQsIHMgPSBiZXN0LnJpZGdlLmxhbWJkYSwgbmV3eCA9IFhfdGVzdCkKcmlkZ2Vfcm1zZS5vcHQgPC0gc3FydChtZWFuKCh5X3Rlc3QgLSByaWRnZV9wcmVkaWN0aW9ucy5vcHQpXjIpKQoKIyBFbGFzdGljIE5ldCAoQ29tYmluYXRpb24gb2YgTDEgYW5kIEwyKQplbGFzdGljX25ldF9tb2RlbC5vcHQgPC0gZ2xtbmV0KFhfdHJhaW4sIHlfdHJhaW4sIGFscGhhID0gMC41LCBsYW1iZGEgPSAwLjEsc3RhbmRhcmRpemUgPSBUUlVFKQplbGFzdGljX25ldF9wcmVkaWN0aW9ucy5vcHQgPC0gcHJlZGljdChlbGFzdGljX25ldF9tb2RlbC5vcHQsIHMgPSAwLjEsIG5ld3ggPSBYX3Rlc3QpCmVsYXN0aWNfbmV0X3Jtc2Uub3B0IDwtIHNxcnQobWVhbigoeV90ZXN0IC0gZWxhc3RpY19uZXRfcHJlZGljdGlvbnMub3B0KV4yKSkKClJNU0Uub3B0ID0gY2JpbmQoTEFTU08ub3B0ID0gbGFzc29fcm1zZS5vcHQsIAogICAgICAgICAgICAgICAgIFJpZGdlLm9wdCA9ICByaWRnZV9ybXNlLm9wdCwgCiAgICAgICAgICAgICAgICAgRWxhc3RpY25ldC5vcHQgPSBlbGFzdGljX25ldF9ybXNlLm9wdCkKCnBhbmRlcihSTVNFLm9wdCkKYGBgCgpUaGUgb3B0aW1hbCBsYW1iZGEgZm9yIGVhY2ggdHlwZSBvZiBsaW5lYXIgcmVncmVzc2lvbiBpcyBzaG93biBhYm92ZS4KCiMjIExBU1NPIFJlZ3Jlc3Npb24gRXF1YXRpb24KCk5vdywgYSBmaW5hbCBtb2RlbCB3aWxsIGJlIGV4dHJhY3RlZCB1c2luZyBMQVNTTywgUmlkZ2UsIGFuZCBFbGFzdGljIE5ldC4KCmBgYHtyfQojTGFzc28KIyBFeHRyYWN0IGNvZWZmaWNpZW50cyB3aXRoIG5hbWVzIGZyb20gZ2xtbmV0CmNvZWZfbGFzc28gPC0gY29lZihjdl9sYXNzbywgcyA9IGJlc3QubGFzc28ubGFtYmRhKQpjb2VmX2RmIDwtIGFzLmRhdGEuZnJhbWUoYXMubWF0cml4KGNvZWZfbGFzc28pKQpjb2VmX2RmJGZlYXR1cmUgPC0gcm93bmFtZXMoY29lZl9kZikKY29sbmFtZXMoY29lZl9kZilbMV0gPC0gImNvZWZmaWNpZW50IgoKIyBGaWx0ZXIgbm9uLXplcm8gY29lZmZpY2llbnRzCm5vbnplcm9fY29lZnMgPC0gc3Vic2V0KGNvZWZfZGYsIGNvZWZmaWNpZW50ICE9IDApCgojIFNlcGFyYXRlIGludGVyY2VwdAppbnRlcmNlcHQgPC0gcm91bmQobm9uemVyb19jb2VmcyRjb2VmZmljaWVudFtub256ZXJvX2NvZWZzJGZlYXR1cmUgPT0gIihJbnRlcmNlcHQpIl0sIDQpCm5vbnplcm9fdGVybXMgPC0gc3Vic2V0KG5vbnplcm9fY29lZnMsIGZlYXR1cmUgIT0gIihJbnRlcmNlcHQpIikKCiMgQnVpbGQgbW9kZWwgZXF1YXRpb24gc3RyaW5nCmVxdWF0aW9uIDwtIHBhc3RlMChyb3VuZChub256ZXJvX3Rlcm1zJGNvZWZmaWNpZW50LCA0KSwgIioiLCBub256ZXJvX3Rlcm1zJGZlYXR1cmUpCmNhdCgiTW9kZWwgZXF1YXRpb246IHkgPSIsIGludGVyY2VwdCwgIisiLCBwYXN0ZShlcXVhdGlvbiwgY29sbGFwc2UgPSAiICsgIiksICJcbiIpCgoKYGBgCgojIyBSaWRnZSBSZWdyZXNzaW9uIEVxdWF0aW9uCgpgYGB7cn0KCiMgRXh0cmFjdCBjb2VmZmljaWVudHMgd2l0aCBuYW1lcyBmcm9tIGdsbW5ldApjb2VmX3JpZGdlIDwtIGNvZWYoY3ZfcmlkZ2UsIHMgPSBiZXN0LnJpZGdlLmxhbWJkYSkKY29lZl9kZiA8LSBhcy5kYXRhLmZyYW1lKGFzLm1hdHJpeChjb2VmX3JpZGdlKSkKY29lZl9kZiRmZWF0dXJlIDwtIHJvd25hbWVzKGNvZWZfZGYpCmNvbG5hbWVzKGNvZWZfZGYpWzFdIDwtICJjb2VmZmljaWVudCIKCiMgRmlsdGVyIG5vbi16ZXJvIGNvZWZmaWNpZW50cwpub256ZXJvX2NvZWZzIDwtIHN1YnNldChjb2VmX2RmLCBjb2VmZmljaWVudCAhPSAwKQoKIyBTZXBhcmF0ZSBpbnRlcmNlcHQKaW50ZXJjZXB0IDwtIHJvdW5kKG5vbnplcm9fY29lZnMkY29lZmZpY2llbnRbbm9uemVyb19jb2VmcyRmZWF0dXJlID09ICIoSW50ZXJjZXB0KSJdLCA0KQpub256ZXJvX3Rlcm1zIDwtIHN1YnNldChub256ZXJvX2NvZWZzLCBmZWF0dXJlICE9ICIoSW50ZXJjZXB0KSIpCgojIEJ1aWxkIG1vZGVsIGVxdWF0aW9uIHN0cmluZwplcXVhdGlvbiA8LSBwYXN0ZTAocm91bmQobm9uemVyb190ZXJtcyRjb2VmZmljaWVudCwgNCksICIqIiwgbm9uemVyb190ZXJtcyRmZWF0dXJlKQpjYXQoIk1vZGVsIGVxdWF0aW9uOiB5ID0iLCBpbnRlcmNlcHQsICIrIiwgcGFzdGUoZXF1YXRpb24sIGNvbGxhcHNlID0gIiArICIpLCAiXG4iKQoKCgpgYGAKCiMjIEVsYXN0aWMgTmV0IFJlZ3Jlc3Npb24gRXF1YXRpb24KCmBgYHtyfQoKIyBFeHRyYWN0IGNvZWZmaWNpZW50cyB3aXRoIG5hbWVzIGZyb20gZ2xtbmV0CmNvZWZfZWxhc3RpYyA8LSBjb2VmKGN2X2VsYXN0aWNfbmV0LCBzID0gYmVzdC5lbGFzdGljLm5ldC5sYW1iZGEpCmNvZWZfZGYgPC0gYXMuZGF0YS5mcmFtZShhcy5tYXRyaXgoY29lZl9lbGFzdGljKSkKY29lZl9kZiRmZWF0dXJlIDwtIHJvd25hbWVzKGNvZWZfZGYpCmNvbG5hbWVzKGNvZWZfZGYpWzFdIDwtICJjb2VmZmljaWVudCIKCiMgRmlsdGVyIG5vbi16ZXJvIGNvZWZmaWNpZW50cwpub256ZXJvX2NvZWZzIDwtIHN1YnNldChjb2VmX2RmLCBjb2VmZmljaWVudCAhPSAwKQoKIyBTZXBhcmF0ZSBpbnRlcmNlcHQKaW50ZXJjZXB0IDwtIHJvdW5kKG5vbnplcm9fY29lZnMkY29lZmZpY2llbnRbbm9uemVyb19jb2VmcyRmZWF0dXJlID09ICIoSW50ZXJjZXB0KSJdLCA0KQpub256ZXJvX3Rlcm1zIDwtIHN1YnNldChub256ZXJvX2NvZWZzLCBmZWF0dXJlICE9ICIoSW50ZXJjZXB0KSIpCgojIEJ1aWxkIG1vZGVsIGVxdWF0aW9uIHN0cmluZwplcXVhdGlvbiA8LSBwYXN0ZTAocm91bmQobm9uemVyb190ZXJtcyRjb2VmZmljaWVudCwgNCksICIqIiwgbm9uemVyb190ZXJtcyRmZWF0dXJlKQpjYXQoIk1vZGVsIGVxdWF0aW9uOiB5ID0iLCBpbnRlcmNlcHQsICIrIiwgcGFzdGUoZXF1YXRpb24sIGNvbGxhcHNlID0gIiArICIpLCAiXG4iKQoKCgpgYGAKCmBgYHtyfQpsYXNzby5lcnJvciA8LSBtaW4oY3ZfbGFzc28kY3ZtKQpyaWRnZS5lcnJvciA8LSBtaW4oY3ZfcmlkZ2UkY3ZtKQplbmV0LmVycm9yICA8LSBtaW4oY3ZfZWxhc3RpY19uZXQkY3ZtKQoKbW9kZWwuZXJyb3JzIDwtIGRhdGEuZnJhbWUoCiAgTW9kZWwgPSBjKCJMQVNTTyIsICJSaWRnZSIsICJFbGFzdGljIE5ldCIpLAogIENWX0Vycm9yID0gYyhsYXNzby5lcnJvciwgcmlkZ2UuZXJyb3IsIGVuZXQuZXJyb3IpCikKCnBhbmRlcihtb2RlbC5lcnJvcnMpCgpgYGAKCiMjIENvbmNsdXNpb24gZm9yIFJlZ3VsYXJpemVkIFJlZ3Jlc3Npb24gTW9kZWxpbmcKClRoZSB0YWJsZSBhYm92ZSBzaG93cyB0aGUgTVNFIHZhbHVlcyBvciBjcm9zcy12YWxpZGF0ZWQgZXJyb3JzIGZvciBvdXIgdGhyZWUgbW9kZWxzLiBBIHNtYWxsZXIgdmFsdWUgaW5kaWNhdGVzIGEgbW9kZWwgd2l0aCBncmVhdGVyIHBlcmZvcm1hbmNlLiBUaGUgTEFTU08gbGluZWFyIHJlZ3Jlc3Npb24gbW9kZWwgb3V0IHBlcmZvcm1zIGJvdGggdGhlIFJpZGdlIGFuZCBFbGFzdGljIE5ldCBtb2RlbC4gV2hlbiBwcmVkaWN0aW5nIGZpbmFuY2lhbCBsb3NzIGNhdXNlZCBieSBjeWJlciBzZWN1cml0eSB0aHJlYXRzLCB0aGUgTEFTU08gbGluZXIgcmVncmVzc2lvbiBtb2RlbCB3aWxsIGJlIHRoZSBtb3N0IGVmZmljaWVudC4KCiQkCgpcdGV4dHtGaW5hbmNpYWwgTG9zcyBpbiBNaWxsaW9uc30gPSA1MC41MzY5ICsgNC44MThcdGltZXMgXHRleHR7QXR0YWNrIFR5cGUgRERvU30gLSAwLjQxNzFcdGltZXMgXHRleHR7VGFyZ2V0IEluZHVzdHJ5IEVkdWNhdGlvbn0gKyAyLjMyNFx0aW1lcyBcdGV4dHtUYXJnZXQgSW5kdXN0cnkgR292ZXJubWVudH0gLSAwLjM0NjRcdGltZXMgXHRleHR7VGFyZ2V0IEluZHVzdHJ5IEhlYWx0aGNhcmV9ICsgMC4yNjVcdGltZXMgXHRleHQge0F0dGFjayBTb3VyY2UgSGFja2VyIEdyb3VwfSAtIDAuNTMzNVx0aW1lcyBcdGV4dHtBdHRhY2sgU291cmNlIEluc2lkZXJ9ICsgMC4wMDY1XHRpbWVzIFx0ZXh0IHtEZWZlbnNlIE1lY2hhbmlzbSBVc2VkIEFudGl2aXJ1c30KCiQkCgojIFN1cHBvcnQgVmVjdG9yIFJlZ3Jlc3Npb24KCkZvciB0aGlzIHNlY3Rpb24gb2YgdGhlIGFuYWx5c2lzLCBsaW5lYXIgYW5kIHJhZGlhbCBiYXNpcyBmdW5jdGlvbnMgd2lsbCBiZSBmaXQgdXNpbmcgc3VwcG9ydCB2ZWN0b3IgcmVncmVzc2lvbiBhbmQgYW4gb3JkaW5hcnkgbGVhc3Qgc3F1YXJlcyByZWdyZXNzaW9uIG1vZGVsIHdpbGwgYmUgZml0IHVzaW5nIHN0ZXAtd2lzZSB2YXJpYWJsZSBzZWxlY3Rpb24uCgpgYGB7cn0KCmN5YmVyIDwtIHJlYWQuY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vR2FiYnlLOC9EYXRhc2V0cy9yZWZzL2hlYWRzL21haW4vR2xvYmFsX0N5YmVyc2VjdXJpdHlfVGhyZWF0c18yMDE1LTIwMjQuY3N2JykKCiNPbmUtSG90IEVuY29kaW5nCmR1bW15IDwtIGR1bW15VmFycygifi4iLCBkYXRhPWN5YmVyKQpjeWJlcjI8LWRhdGEuZnJhbWUocHJlZGljdChkdW1teSwgbmV3ZGF0YT1jeWJlcikpCgojIyMjIwojIFNwbGl0IGRhdGEgaW50byBmZWF0dXJlcyAoWCkgYW5kIHRhcmdldCAoeSkKWCA8LSBjeWJlcjJbLCAtMjVdICAjIEFsbCBjb2x1bW5zIGV4Y2VwdCB0aGUgdGFyZ2V0IHZhcmlhYmxlCnkgPC0gY3liZXIyWywgMjVdICAgIyBUYXJnZXQgdmFyaWFibGUgKEZpbmFuY2lhbCBMb3NzIGluIE1pbGxpb25zKQoKIyBjcmVhdGUgZHVtbXkgdmFyaWFibGVzCgoKCiMjIyMjCiMgU3BsaXQgZGF0YSBpbnRvIHRyYWluaW5nIGFuZCB0ZXN0aW5nIHNldHMKc2V0LnNlZWQoMTIzKQp0cmFpbi5pbmRleCA8LSBzYW1wbGUoMTpucm93KGN5YmVyMiksIDAuOCAqIG5yb3coY3liZXIyKSkKWC50cmFpbiA8LSBYW3RyYWluLmluZGV4LCBdCnkudHJhaW4gPC0geVt0cmFpbi5pbmRleF0KWC50ZXN0IDwtIFhbLXRyYWluLmluZGV4LCBdCnkudGVzdCA8LSB5Wy10cmFpbi5pbmRleF0KCiMjIyMjCmN5YmVyMi50cmFpbiA8LSBhcy5kYXRhLmZyYW1lKGN5YmVyMlt0cmFpbi5pbmRleCwgXSkKY3liZXIyLnRlc3QgPC0gY3liZXIyWy10cmFpbi5pbmRleCwgXQojIyMjIwojIyBTZXQgdXAgY3VzdG9tIGNyb3NzLXZhbGlkYXRpb24gY29udHJvbApteV90dW5lX2NvbnRyb2wgPC0gdHVuZS5jb250cm9sKAogIGNyb3NzID0gNSwgICMgVXNlIDUtZm9sZCBjcm9zcy12YWxpZGF0aW9uLCB0aGUgZGVmYXVsdCBpcyAxMC1mb2xkIGNyb3NzLXZhbGlkYXRpb24KICBucmVwZWF0ID0gMSAjIE51bWJlciBvZiByZXBldGl0aW9ucyAoZm9yIHJlcGVhdGVkIGNyb3NzLXZhbGlkYXRpb24pCikKIyMjIyMKIyBQZXJmb3JtIGdyaWQgc2VhcmNoIGZvciBoeXBlcnBhcmFtZXRlciB0dW5pbmc6IFJCRiBrZXJuZWwgaXMgdXNlZAp0dW5lLlJCRiA8LSB0dW5lKHN2bSwKICAgICAgICAgICAgICAgICB0cmFpbi54ID0gWC50cmFpbiwgCiAgICAgICAgICAgICAgICAgdHJhaW4ueSA9IHkudHJhaW4sIAogICAgICAgICAgICAgICAgICAgIHJhbmdlcyA9IGxpc3QoZXBzaWxvbiA9IHNlcSgwLjEsIDAuNSwgMC4xKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3N0ID0gYygxLCAxMCwgMTAwKSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBnYW1tYSA9IGMoMC4wMSwgMC4xLCAxKSksICMgSHlwZXJwYXIgaW4gUkJGCiAgICAgICAgICAgICAgICAgICAgdHVuZWNvbnRyb2wgPSBteV90dW5lX2NvbnRyb2wgICAgIyA1LWZvbGQgY3Jvc3MtdmFsaWRhdGlvbgoKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKQoKIyMjIwojIERpc3BsYXkgdGhlIGJlc3QgcGFyYW1ldGVycwojcHJpbnQodHVuZS5SQkYkYmVzdC5wYXJhbWV0ZXJzKQojIyMjIwojIFRyYWluIHRoZSBmaW5hbCBtb2RlbCB1c2luZyB0aGUgYmVzdCBwYXJhbWV0ZXJzCmZpbmFsLlJCRjwtIHN2bShYLnRyYWluLCB5LnRyYWluLCAKICAgICAgICAgICAgICAgICAgIHR5cGUgPSAiZXBzLXJlZ3Jlc3Npb24iLCAgIyBVc2UgIm51LXJlZ3Jlc3Npb24iIGZvciBudS1TVlIKICAgICAgICAgICAgICAgICAgIGtlcm5lbCA9ICJyYWRpYWwiLCAKICAgICAgICAgICAgICAgICAgIGVwc2lsb24gPSB0dW5lLlJCRiRiZXN0LnBhcmFtZXRlcnMkZXBzaWxvbiwgCiAgICAgICAgICAgICAgICAgICBjb3N0ID0gdHVuZS5SQkYkYmVzdC5wYXJhbWV0ZXJzJGNvc3QsIAogICAgICAgICAgICAgICAgICAgZ2FtbWEgPSB0dW5lLlJCRiRiZXN0LnBhcmFtZXRlcnMkZ2FtbWEpCiMjIyMjCiMgTWFrZSBwcmVkaWN0aW9ucyBvbiB0aGUgdGVzdCBzZXQKcHJlZC5SQkYgPC0gcHJlZGljdChmaW5hbC5SQkYsIFgudGVzdCkKCiMgRXZhbHVhdGUgcGVyZm9ybWFuY2UKbXNlLlJCRiA8LSBtZWFuKCh5LnRlc3QgLSBwcmVkLlJCRileMikgICAgIyBtZWFuIHNxdWFyZSBlcnJvcgptYWUuUkJGIDwtIG1lYW4oYWJzKHkudGVzdCAtIHByZWQuUkJGKSkgICAjIG1lYW4gYWJzb2x1dGUgZXJyb3IKCiMjIyMgbGluZWFyIGtlcm5lbAoKIyBQZXJmb3JtIGdyaWQgc2VhcmNoIGZvciBoeXBlcnBhcmFtZXRlciB0dW5pbmc6IFJCRiBrZXJuZWwgaXMgdXNlZAp0dW5lLmxpbiA8LSB0dW5lKHN2bSwgdHJhaW4ueCA9IFgudHJhaW4sIHRyYWluLnkgPSB5LnRyYWluLCAKICAgICAgICAgICAgICAgICAgICByYW5nZXMgPSBsaXN0KGVwc2lsb24gPSBzZXEoMC4xLCAwLjUsIDAuMSksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29zdCA9IGMoMSwgMTAsIDEwMCkpLCAKICAgICAgICAgICAgICAgICAgICB0dW5lY29udHJvbCA9IG15X3R1bmVfY29udHJvbCAjIDUtZm9sZCBjcm9zcy12YWxpZGF0aW9uCiAgICAgICAgICAgICAgICAgICAgKQojIyMjCiMgRGlzcGxheSB0aGUgYmVzdCBwYXJhbWV0ZXJzCiNwcmludCh0dW5lLmxpbiRiZXN0LnBhcmFtZXRlcnMpCiMjIyMjCiMgVHJhaW4gdGhlIGZpbmFsIG1vZGVsIHVzaW5nIHRoZSBiZXN0IHBhcmFtZXRlcnMKZmluYWwubGluPC0gc3ZtKFgudHJhaW4sIHkudHJhaW4sIAogICAgICAgICAgICAgICAgICAgdHlwZSA9ICJlcHMtcmVncmVzc2lvbiIsICAjIFVzZSAibnUtcmVncmVzc2lvbiIgZm9yIG51LVNWUgogICAgICAgICAgICAgICAgICAga2VybmVsID0gImxpbmVhciIsIAogICAgICAgICAgICAgICAgICAgZXBzaWxvbiA9IHR1bmUubGluJGJlc3QucGFyYW1ldGVycyRlcHNpbG9uLCAKICAgICAgICAgICAgICAgICAgIGNvc3QgPSB0dW5lLmxpbiRiZXN0LnBhcmFtZXRlcnMkY29zdCkKIyMjIyMKIyBNYWtlIHByZWRpY3Rpb25zIG9uIHRoZSB0ZXN0IHNldApwcmVkLmxpbiA8LSBwcmVkaWN0KGZpbmFsLmxpbiwgWC50ZXN0KQoKIyBFdmFsdWF0ZSBwZXJmb3JtYW5jZQptc2UubGluIDwtIG1lYW4oKHkudGVzdCAtIHByZWQubGluKV4yKSAgICAjIG1lYW4gc3F1YXJlIGVycm9yCm1hZS5saW4gPC0gbWVhbihhYnMoeS50ZXN0IC0gcHJlZC5saW4pKQoKClJCRiA8LSB0dW5lLlJCRiRiZXN0LnBhcmFtZXRlcnMKTGluZWFyIDwtIHR1bmUubGluJGJlc3QucGFyYW1ldGVycwpwYW5kZXIoUkJGLCBjYXB0aW9uPSdSQkYgQmVzdCBQYXJhbWV0ZXJzJykKcGFuZGVyKExpbmVhciwgY2FwdGlvbj0nTGluZWFyIFNWUiBCZXN0IFBhcmFtZXRlcnMnKQoKYGBgCgpUaGUgdGFibGVzIGFib3ZlIHNob3cgdGhlIGZpbmUgdHVuZWQgYmVzdCBwYXJhbWV0ZXJzIGZvciBib3RoIHN1cHBvcnQgdmVjdG9yIHJlZ3Jlc3Npb24gbW9kZWxzLgoKYGBge3IgZmlnLmFsaWduPSdjZW50ZXInLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD01LCBmaWcuY2FwPSdUaGUgcGxvdHMgYXJlIGEgZGlhZ25vc3RpYyBwbG90IGZvciB0aGUgbGVhc3Qgc3F1YXJlcyByZWdyZXNzaW9uIG1vZGVsLid9CgojIyBvcmRpbmFyeSBMU0UgcmVncmVzc2lvbiBtb2RlbCB3aXRoIHN0ZXB3aXNlIHZhcmlhYmxlIHNlbGVjdGlvbgpsc2UuZml0IDwtIGxtKEZpbmFuY2lhbC5Mb3NzLi5pbi5NaWxsaW9uLi4ufi4sZGF0YT1jeWJlcjIudHJhaW4pCkFJQy5maXQgPC0gc3RlcEFJQyhsc2UuZml0LGRpcmVjdGlvbj0iYm90aCIsIHRyYWNlID0gRkFMU0UpCnByZWQubHNlIDwtIHByZWRpY3QoQUlDLmZpdCwgWC50ZXN0KQptc2UubHNlIDwtIG1lYW4oKHkudGVzdCAtIHByZWQubHNlKV4yKSAgICAjIG1lYW4gc3F1YXJlIGVycm9yCm1hZS5sc2UgPC0gbWVhbihhYnMoeS50ZXN0IC0gcHJlZC5sc2UpKSAgICMgbWVhbiBhYnNvbHV0ZSBlcnJvcgojIyMKcGFyKG1mcm93PWMoMiwyKSwgbWFyPWMoMiwyLDIsMikpCnBsb3QoQUlDLmZpdCkKCmBgYAoKVGhlIG1vZGVsIGFib3ZlIHNhdGlzZmllcyB0aGUgbGluZWFyIHJlZ3Jlc3Npb24gYXNzdW1wdGlvbnMgYW5kIHdpbGwgYmUgdXNlZCB0byBoZWxwIGNvbXBhcmUgcGVyZm9ybWFuY2UuCgojIyBDb21wYXJpbmcgUmVncmVzc2lvbiBNb2RlbHMKCkluIHRoaXMgc2VjdGlvbiB3ZSB3aWxsIGxvb2sgYXQgdGhlIHBlcmZvcm1hbmNlIG9mIG91ciBsZWFzdCBzcXVhcmVzIHJlZ3Jlc3Npb24gbW9kZWwgYWZ0ZXIgc3RlcHdpc2UgdmFyaWFibGUgc2VsZWN0aW9uIHdpdGggb3VyIGxpbmVhciBhbmQgcmFkaWFsIGJhc2lzIGZ1bmN0aW9uIG1vZGVscyBmcm9tIHN1cHBvcnQgdmVjdG9yIHJlZ3Jlc3Npb24uV2Ugd2lsbCBjb21wYXJlIHRoZSBtb2RlbCB1c2luZyBNU0UgYW5kIE1BRSB2YWx1ZXMuCgpgYGB7cn0KIyMjClBlcmZvcm1hbmNlIDwtIGRhdGEuZnJhbWUoUkJGLlNWUj1jKG1zZS5SQkYsIG1hZS5SQkYpLAogICAgICAgICAgICAgICAgICAgICAgICAgIExpbmVhci5TVlIgPSBjKG1zZS5saW4sIG1hZS5saW4pLAogICAgICAgICAgICAgICAgICAgICAgICAgIExTRS5SZWcgPWMobXNlLmxzZSwgbWFlLmxzZSkpCnJvdy5uYW1lcyhQZXJmb3JtYW5jZSkgPC0gYygiTVNFIiwgIk1BRSIpCiMjCnBhbmRlcihQZXJmb3JtYW5jZSkKYGBgCgpUaGUgbGluZWFyIGFuZCBsZWFzdCBzcXVhcmVzIG1vZGVsIHBlcmZvcm1lZCBiZXR0ZXIgdGhhbiB0aGUgcmFkaWFsIGJhc2lzIGZ1bmN0aW9uIG1vZGVsLiBUaGUgdHdvIG1vZGVscyBwZXJmb3JtZWQgc2ltaWxhcmx5LCBidXQgdGhlIGxlYXN0IHNxdWFyZXMgbW9kZWwgcGVyZm9ybWVkIHNsaWdodGx5IGJldHRlciBhbmQgd2lsbCBiZSBjaG9zZW4gYXMgdGhlIGJlc3QgbW9kZWwgZm9yIHRoZSBkYXRhLgoKIyMgQ29uY2x1c2lvbiBmb3IgU3VwcG9ydCBWZWN0b3IgUmVncmVzc2lvbgoKQmFzZWQgb24gb3VyIE1TRSBhbmQgTUFFIHNjb3Jlcywgb3VyIGxlYXN0IHNxdWFyZXMgZXN0aW1hdGlvbiBoYXMgdGhlIGJlc3QgbW9kZWwgYmFzZWQgb24gcGVyZm9ybWFuY2UgaW4gY29tcGFyaXNvbiB0byBzdXBwb3J0IHZlY3RvciByZWdyZXNzaW9uIG9uIGxpbmVhciBhbmQgcmFkaWFsIGJhc2lzIGZ1bmN0aW9uLiBJdCBoYXMgbG93ZXIgTVNFIGFuZCBNQUUgc2NvcmVzIGluZGljYXRpbmcgYSBiZXR0ZXIgZml0IG1vZGVsLiBPdXIgZmluYWwgYmVzdCBtb2RlbCBpczoKCiQkClx0ZXh0e0ZpbmFuY2lhbCBMb3NzIGluIE1pbGxpb25zfSA9IDUxLjI3ICsgNC44MThcdGltZXMgXHRleHR7Q291bnRyeUdlcm1hbnl9IC0gMy41MjVcdGltZXMgXHRleHR7Q291bnRyeUluZGlhfSAtIDIuMzI0XHRpbWVzIFx0ZXh0e0F0dGFja1NvdXJjZUluc2lkZXJ9CiQkCg==